#[get("/library/reset_group_topic?<id>")]
fn reset_group_topic(id: usize, state: State<MySqlDriver>) -> String {
    let pool: Pool = Pool::new(state.driver.as_str()).unwrap();
    let mut conn: PooledConn = pool.get_conn().unwrap();
    let sql: String = format!("UPDATE `group_topic` SET `status` = 0 WHERE `id` = {}", id);
    let _ = conn.exec_drop(sql.clone(), ());
    return "success:".to_string();
}

#[derive(FromForm)]
struct GroupUpload {
    group_type: String,
    group_number: String,
    examine: usize,
    publish: usize
}

#[post("/library/upload_group", data = "<form>")]
fn upload_group(form: Form<GroupUpload>, _cookies: Cookies, state: State<MySqlDriver>) -> String {
    let mut except_vec: Vec<char> = Vec::new();
    except_vec.push('\'');
    except_vec.push('"');
    except_vec.push('\\');
    let group_type_hostr: HoString = HoString::copy_string(form.group_type.clone());
    let group_number_hostr: HoString = HoString::copy_string(form.group_number.clone());
    if group_type_hostr.length() == 0 || group_number_hostr.length() == 0 {
        return "fail:表单不能有空".to_string();
    }
    if group_type_hostr.contains_char_vec(except_vec.clone(), 0) == true ||
        group_number_hostr.contains_char_vec(except_vec.clone(), 0) == true {
        return "fail:表单值不能包含引号和斜杠".to_string();
    }

    let pool_result: Result<Pool, mysql::Error> = Pool::new(state.driver.as_str());
    let pool: Pool;
    if let Ok(p) = pool_result {
        pool = p;
    } else {
        return "fail:无法建立数据库连接".to_string();
    }
    let conn_result: Result<PooledConn, mysql::Error> = pool.get_conn();
    let mut conn: PooledConn;
    if let Ok(c) = conn_result {
        conn = c;
    } else {
        return "fail:无法获取数据库连接".to_string();
    }

    let mut number_index: usize = 0;
    loop {
        number_index += 1;
        let group_sql: String = format!("SELECT COUNT(`id`) AS `count` FROM `tag_group` WHERE `number` = '{}{}'", form.group_number.as_str(), number_index);
        let row: Row = conn.query_first(group_sql.clone()).unwrap().unwrap();
        let group_count: usize = from_row(row);
        if group_count == 0 {
            break;
        }
    }

    let group_name: String = format!("{}{}", form.group_number.as_str(), number_index);
    let mut sql: String = format!("INSERT INTO `tag_group`(`type`, `number`, `admin_id_examine`, `admin_id_publish`) VALUES(:group_type, :group_name, :examine, :publish)");
    if let Err(_) = conn.exec_drop(sql.clone(), params![
        "group_type" => form.group_type.as_str(),
        "group_name" => group_name.as_str(),
        "examine" => form.examine,
        "publish" => form.publish
    ]) {
        return "fail:小组添加失败".to_string();
    }
    let insert_id: u64 = conn.last_insert_id();
    HoFile::write_file(format!("ws/ws_group/{}.txt", insert_id).as_str(), format!("{}|{}", form.examine, form.publish).as_str());
    sql = "SELECT `id` FROM `topic` ORDER BY `id` ASC".to_string();
    let mut group_topic_sql: String = "INSERT INTO `group_topic`(`group_id`, `topic_id`, `status`, `update_datetime`) VALUES".to_string();
    let mut i: usize = 0;
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    for row in rows {
        let topic_id: usize = from_row(row);
        if i > 0 {
            group_topic_sql.push_str(",");
        }
        group_topic_sql.push_str(format!("({}, {}, 0, 0)", insert_id, topic_id).as_str());
        i += 1;
    }
    if let Err(_) = conn.exec_drop(group_topic_sql.clone(), ()) {
        return "fail:小组分配选题失败".to_string();
    } else {
        return "success:".to_string();
    }
}

#[derive(FromForm)]
struct GroupUpdate {
    id: usize,
    group_type: String,
    group_number: String,
    examine: usize,
    publish: usize
}

#[post("/library/update_group", data = "<form>")]
fn update_group(form: Form<GroupUpdate>, _cookies: Cookies, state: State<MySqlDriver>) -> String {
    let mut except_vec: Vec<char> = Vec::new();
    except_vec.push('\'');
    except_vec.push('"');
    except_vec.push('\\');
    let group_type_hostr: HoString = HoString::copy_string(form.group_type.clone());
    let group_number_hostr: HoString = HoString::copy_string(form.group_number.clone());
    if group_type_hostr.length() == 0 || group_number_hostr.length() == 0 {
        return "fail:表单不能有空".to_string();
    }
    if group_type_hostr.contains_char_vec(except_vec.clone(), 0) == true ||
        group_number_hostr.contains_char_vec(except_vec.clone(), 0) == true {
        return "fail:表单值不能包含引号和斜杠".to_string();
    }

    let pool_result: Result<Pool, mysql::Error> = Pool::new(state.driver.as_str());
    let pool: Pool;
    if let Ok(p) = pool_result {
        pool = p;
    } else {
        return "fail:无法建立数据库连接".to_string();
    }
    let conn_result: Result<PooledConn, mysql::Error> = pool.get_conn();
    let mut conn: PooledConn;
    if let Ok(c) = conn_result {
        conn = c;
    } else {
        return "fail:无法获取数据库连接".to_string();
    }

    let sql: String = "UPDATE `tag_group` SET `type` = :group_type, `number` = :group_number, `admin_id_examine` = :examine, `admin_id_publish` = :publish WHERE `id` = :id".to_string();
    if let Err(_) = conn.exec_drop(sql.clone(), params![
        "group_type" => form.group_type.as_str(),
        "group_number" => form.group_number.as_str(),
        "examine" => form.examine,
        "publish" => form.publish,
        "id" => form.id
    ]) {
        return "fail:更新失败".to_string();
    }
    HoFile::write_file(format!("ws/ws_group/{}.txt", form.id).as_str(), format!("{}|{}", form.examine, form.publish).as_str());
    return "success:".to_string();
}

#[get("/add_group")]
fn add_group(cookies: Cookies, state: State<MySqlDriver>) -> Response<'static> {
    let mut res = Response::new();
    res.set_header(ContentType::HTML);

    // mod_id: String, 
    // mod_menu_open: String, 
    // sub_mod_id: String, 
    // page_title: String, 
    // title: String
    let header: String = get_header(
        "group-mod".to_string(), 
        "group-mod-menu-open".to_string(), 
        String::new(),
        "用户后台 - 添加小组".to_string(), 
        "添加小组".to_string(), &cookies,
        &state);

    let pool_result: Result<Pool, mysql::Error> = Pool::new(state.driver.as_str());
    let pool: Pool;
    if let Ok(p) = pool_result {
        pool = p;
    } else {
        res.set_sized_body(Cursor::new("无法建立数据库连接".to_string()));
        return res;
    }
    let conn_result: Result<PooledConn, mysql::Error> = pool.get_conn();
    let mut conn: PooledConn;
    if let Ok(c) = conn_result {
        conn = c;
    } else {
        res.set_sized_body(Cursor::new("无法获取数据库连接".to_string()));
        return res;
    }
    
    let mut sql: String = "SELECT `type` AS `topic_type` FROM `topic`".to_string();
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    let mut type_button_html: String = String::new();
    let type_list: Vec<String> = Vec::new();
    for row in rows {
        let topic_type: String = from_row(row);
        let topic_type_hostr: HoString = HoString::copy_string(topic_type);
        let topic_type_list: Vec<HoString> = topic_type_hostr.split_bytes(",".as_bytes());
        for topic_type_item in topic_type_list {
            if topic_type_item.length() == 0 {
                continue;
            }
            if type_list.contains(&topic_type_item.to_string()) == false {
                type_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action\" id=\"type{}\" onclick=\"active_type('{}')\">{}</button>", topic_type_item.to_str(), topic_type_item.to_str(), topic_type_item.to_str()).as_str());
            }
        }
    }
    
    sql = "SELECT `id`, `account` FROM `user` WHERE `is_admin` = 1".to_string();
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    let mut examine_button_html: String = String::new();
    for row in rows {
        let (id, account): (usize, String) = from_row(row);
        examine_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action\" id=\"examine{}\" onclick=\"active_examine({})\">{}</button>", id, id, account.as_str()).as_str());
    }

    sql = "SELECT `id`, `account` FROM `user` WHERE `is_admin` = 2".to_string();
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    let mut publish_button_html: String = String::new();
    for row in rows {
        let (id, account): (usize, String) = from_row(row);
        publish_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action\" id=\"publish{}\" onclick=\"active_publish({})\">{}</button>", id, id, account.as_str()).as_str());
    }

    sql = "SELECT `movie_name` FROM `topic` ORDER BY `id` ASC".to_string();
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    let mut movie_name_ul: String = String::new();
    let mut li_index: usize = 0;
    let mut is_first: bool = true;
    for row in rows {
        let movie_name: String = from_row(row);
        if li_index % 5 == 0 {
            if is_first {
                movie_name_ul.push_str("<ul class=\"list-group list-group-horizontal\">");
                is_first = false;
            } else {
                movie_name_ul.push_str("</ul><ul class=\"list-group list-group-horizontal\">");
            }
        }
        movie_name_ul.push_str(format!("<li class=\"list-group-item flex-fill\">{}</li>", movie_name.as_str()).as_str());
        li_index += 1;
    }
    movie_name_ul.push_str("</ul>");

    let mut src_vec: Vec<&[u8]> = Vec::new();
    let mut replace_vec: Vec<&[u8]> = Vec::new();

    let footer_string: String = get_footer();
    src_vec.push("{header}".as_bytes());
    src_vec.push("{base_url}".as_bytes());
    src_vec.push("{type_button_html}".as_bytes());
    src_vec.push("{examine_button_html}".as_bytes());
    src_vec.push("{publish_button_html}".as_bytes());
    src_vec.push("{movie_name_ul}".as_bytes());
    src_vec.push("{footer}".as_bytes());
    replace_vec.push(header.as_bytes());
    replace_vec.push(state.base_url.as_bytes());
    replace_vec.push(type_button_html.as_bytes());
    replace_vec.push(examine_button_html.as_bytes());
    replace_vec.push(publish_button_html.as_bytes());
    replace_vec.push(movie_name_ul.as_bytes());
    replace_vec.push(footer_string.as_bytes());

    let mut page_str: HoString = HoFile::read_file_bytes("web/add_group.html");
    page_str = page_str.replace_bytes_vec(src_vec, replace_vec);
    let html: String = page_str.to_str().to_string().to_owned();
    res.set_sized_body(Cursor::new(html));
    return res;
}

#[get("/edit_group?<id>")]
fn edit_group(id: usize, cookies: Cookies, state: State<MySqlDriver>) -> Response<'static> {
    let mut res = Response::new();
    res.set_header(ContentType::HTML);

    // mod_id: String, 
    // mod_menu_open: String, 
    // sub_mod_id: String, 
    // page_title: String, 
    // title: String
    let header: String = get_header(
        "group-mod".to_string(), 
        "group-mod-menu-open".to_string(), 
        String::new(),
        "用户后台 - 编辑小组".to_string(), 
        "编辑小组".to_string(), &cookies,
        &state);

    let pool_result: Result<Pool, mysql::Error> = Pool::new(state.driver.as_str());
    let pool: Pool;
    if let Ok(p) = pool_result {
        pool = p;
    } else {
        res.set_sized_body(Cursor::new("无法建立数据库连接".to_string()));
        return res;
    }
    let conn_result: Result<PooledConn, mysql::Error> = pool.get_conn();
    let mut conn: PooledConn;
    if let Ok(c) = conn_result {
        conn = c;
    } else {
        res.set_sized_body(Cursor::new("无法获取数据库连接".to_string()));
        return res;
    }

    let mut sql: String = format!("SELECT `type` AS `topic_type`, `number`, `admin_id_examine`, `admin_id_publish` FROM `tag_group` WHERE `id` = {} LIMIT 1", id);
    let row_op: Option<Row> = conn.query_first(sql.clone()).unwrap();
    let row: Row;
    if let Some(r) = row_op {
        row = r;
    } else {
        res.set_sized_body(Cursor::new("小组信息查询失败".to_string()));
        return res;
    }
    let (topic_type, number, admin_id_examine, admin_id_publish): (String, String, usize, usize) = from_row(row);
    
    sql = "SELECT `type` AS `topic_type1` FROM `topic`".to_string();
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    let mut type_button_html: String = String::new();
    let mut type_list: Vec<String> = Vec::new();
    for row in rows {
        let topic_type1: String = from_row(row);
        let topic_type_hostr: HoString = HoString::copy_string(topic_type1.clone());
        let topic_type_list: Vec<HoString> = topic_type_hostr.split_bytes(",".as_bytes());
        for topic_type_item in topic_type_list {
            if topic_type_item.length() == 0 {
                continue;
            }
            if type_list.contains(&topic_type_item.to_string()) == false {
                if topic_type_item.compare_bytes(topic_type.as_bytes()) {
                    type_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action active\" id=\"type{}\" onclick=\"active_type('{}')\">{}</button>", topic_type_item.to_str(), topic_type_item.to_str(), topic_type_item.to_str()).as_str());
                } else {
                    type_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action\" id=\"type{}\" onclick=\"active_type('{}')\">{}</button>", topic_type_item.to_str(), topic_type_item.to_str(), topic_type_item.to_str()).as_str());
                }
                type_list.push(topic_type_item.to_string());
            }
        }
    }
    
    sql = "SELECT `id`, `account` FROM `user` WHERE `is_admin` = 1".to_string();
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    let mut examine_button_html: String = String::new();
    for row in rows {
        let (id, account): (usize, String) = from_row(row);
        if id == admin_id_examine {
            examine_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action active\" id=\"examine{}\" onclick=\"active_examine({})\">{}</button>", id, id, account.as_str()).as_str());
        } else {
            examine_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action\" id=\"examine{}\" onclick=\"active_examine({})\">{}</button>", id, id, account.as_str()).as_str());
        }
    }

    sql = "SELECT `id`, `account` FROM `user` WHERE `is_admin` = 2".to_string();
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    let mut publish_button_html: String = String::new();
    for row in rows {
        let (id, account): (usize, String) = from_row(row);
        if id == admin_id_publish {
            publish_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action active\" id=\"publish{}\" onclick=\"active_publish({})\">{}</button>", id, id, account.as_str()).as_str());
        } else {
            publish_button_html.push_str(format!("<button type=\"button\" class=\"list-group-item list-group-item-action\" id=\"publish{}\" onclick=\"active_publish({})\">{}</button>", id, id, account.as_str()).as_str());
        }
    }

    sql = format!("SELECT `t`.`movie_name` FROM `group_topic` AS `gt` INNER JOIN `topic` AS `t` ON `t`.`id` = `gt`.`topic_id` WHERE `gt`.`group_id` = {} AND `gt`.`status` = 0", id);
    let rows: Vec<Row> = conn.query(sql.clone()).unwrap();
    let mut movie_name_ul: String = String::new();
    let mut li_index: usize = 0;
    let mut is_first: bool = true;
    for row in rows {
        let movie_name: String = from_row(row);
        if li_index % 5 == 0 {
            if is_first {
                movie_name_ul.push_str("<ul class=\"list-group list-group-horizontal\">");
                is_first = false;
            } else {
                movie_name_ul.push_str("</ul><ul class=\"list-group list-group-horizontal\">");
            }
        }
        movie_name_ul.push_str(format!("<li class=\"list-group-item flex-fill\">{}</li>", movie_name.as_str()).as_str());
        li_index += 1;
    }
    movie_name_ul.push_str("</ul>");

    let mut src_vec: Vec<&[u8]> = Vec::new();
    let mut replace_vec: Vec<&[u8]> = Vec::new();

    let id_str: String = id.to_string();
    let admin_id_examine_str: String = admin_id_examine.to_string();
    let admin_id_publish_str: String = admin_id_publish.to_string();
    let footer_string: String = get_footer();
    src_vec.push("{header}".as_bytes());
    src_vec.push("{id}".as_bytes());
    src_vec.push("{base_url}".as_bytes());
    src_vec.push("{number}".as_bytes());
    src_vec.push("{admin_id_examine}".as_bytes());
    src_vec.push("{admin_id_publish}".as_bytes());
    src_vec.push("{topic_type}".as_bytes());
    src_vec.push("{type_button_html}".as_bytes());
    src_vec.push("{examine_button_html}".as_bytes());
    src_vec.push("{publish_button_html}".as_bytes());
    src_vec.push("{movie_name_ul}".as_bytes());
    src_vec.push("{footer}".as_bytes());
    replace_vec.push(header.as_bytes());
    replace_vec.push(id_str.as_bytes());
    replace_vec.push(state.base_url.as_bytes());
    replace_vec.push(number.as_bytes());
    replace_vec.push(admin_id_examine_str.as_bytes());
    replace_vec.push(admin_id_publish_str.as_bytes());
    replace_vec.push(topic_type.as_bytes());
    replace_vec.push(type_button_html.as_bytes());
    replace_vec.push(examine_button_html.as_bytes());
    replace_vec.push(publish_button_html.as_bytes());
    replace_vec.push(movie_name_ul.as_bytes());
    replace_vec.push(footer_string.as_bytes());

    let mut page_str: HoString = HoFile::read_file_bytes("web/edit_group.html");
    page_str = page_str.replace_bytes_vec(src_vec, replace_vec);
    let html: String = page_str.to_str().to_string().to_owned();
    res.set_sized_body(Cursor::new(html));
    return res;
}

